package org.easy.core.util;


import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.LockSupport;
import java.util.function.Function;


@Slf4j
public class FunctionThreadQueueWorker {
    private BlockingQueue<ExecuteItem> queue = new LinkedBlockingQueue<>();


    public FunctionThreadQueueWorker(int workerNum) {
        if (workerNum > 100) {
            throw new IllegalArgumentException("workerNum > 100");
        }

        for (int i = 0; i < workerNum; i++) {
            new Thread(this::worker).start();
        }
    }

    private void worker() {
        while (true) {
            ExecuteItem take = null;
            try {
                take = queue.take();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            Object apply = take.getFunction().apply(take.getParamObject());
            take.setResult(apply);
            LockSupport.unpark(take.getMainThread());
            try {
                Thread.sleep(900);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public Object enqueue(Function<Object, Object> function, Object param) {
        try {
            ExecuteItem executeItem = new ExecuteItem();
            executeItem.setMainThread(Thread.currentThread());
            executeItem.setFunction(function);
            executeItem.setParamObject(param);
            queue.put(executeItem);
            LockSupport.park();
            return executeItem.getResult();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return null;
    }


    @Data
    public static class ExecuteItem {

        private Thread mainThread;

        private Function<Object, Object> function;

        private Object paramObject;

        private Object result;

    }
}

